#include "sensortrayconveyer.h"

SensorTrayConveyer::SensorTrayConveyer(SensorTrayOutputElevator *stoe, QObject *parent)
    : Worker(WorkerName::SensorTrayConveyer, parent), stoe(stoe)
{
    stcConfig = new SensorTrayConveyerConfig(this);
    stcConfigFile = new ConfigFile("SensorTrayConveyerConfig", stcConfig,
                                   QString("%1/sensorTrayConveyerConfig.json").arg(getWorkerConfigDir()));
    stcConfigFile->populate();
}

void SensorTrayConveyer::pushOutTray()
{
    checkIsInit();

    AutoResetBool b(&m_beltZCanMove, true);
    if (stoe != nullptr)
    {
        m_beltZCanMove = false;
        if (!stoe->moveToNextInitTrayPos())
        {
            return;
        }
    }

    stcBelt->velocityMove(beltRunDir);
    ErrorHandler::tryToHandleGeneralError<void>(
        [this] {
            QElapsedTimer timer;
            timer.start();
            while (true)
            {
                if (timer.elapsed() > stcConfig->pushOutTrayTimeout())
                {
                    stcBelt->stop();
                    throw GeneralError(workerName(), tr("Push out tray timeout!"));
                }
                if (trayArrivedExit())
                {
                    if (stcConfig->delayAfterPushoutTray() > 0)
                    {
                        QThread::msleep(stcConfig->delayAfterPushoutTray());
                    }
                    stcBelt->stop();
                    break;
                }
                QThread::msleep(10);
            }
        },
        [this] { stcBelt->velocityMove(beltRunDir); });

    if (stoe == nullptr)
    {
        makeSureHasNotTrayAtTheExit(false);
    }
    else
    {
        while (true)
        {
            stcKicker->set(true);
            stcKicker->set(false);
            try
            {
                ErrorHandler::tryToHandleError([this] {
                    if (stcRightTraySensor->get(-1))
                    {
                        throw KickTrayError(WorkerName::SensorTrayConveyer,
                                            tr("SensorTrayConveyer推出Tray, "
                                               "但stcRightTraySensor检测到仍然有Tray!\r\n选项解释:\r\nRetry: 重新检测  "
                                               "ReKick: 重新推Tray"));
                    }
                });
                stoe->setCurrentMagTrayState(MagTrayState::ProductTray);
                stoe->pushEvent(WorkerEvent("moveToNextInitTrayPos"));
                break;
            }
            catch (UnhandledError &ue)
            {
                ue.what();
                continue;    // ReKick
            }
        }
    }
}

void SensorTrayConveyer::makeSureHasNotTrayAtTheExit(bool moveBeltToCheck)
{
    while (detectHasTrayAtTheExit(moveBeltToCheck))
    {
        if (hasAbortEvent())
        {
            return;
        }
        UIOperation::getIns()->getUIResponse("", tr("Please take away the tray at the exit of SensorTrayConveyer!"),
                                             MsgBoxIcon::Information, YesBtn);
    }
}

bool SensorTrayConveyer::detectHasTrayAtTheExit(bool moveBeltToCheck)
{
    if (!moveBeltToCheck)
    {
        return isAnySensorGotSignal();
    }
    if (isAnySensorGotSignal())
    {
        return true;
    }
    stcBelt->velocityMove(beltRunDir);
    QElapsedTimer timer;
    timer.start();
    while (timer.elapsed() < stcConfig->detectHasTrayMaxTime())
    {
        if (isAnySensorGotSignal())
        {
            break;
        }
        QThread::msleep(10);
    }
    stcBelt->stop();
    return isAnySensorGotSignal();
}

bool SensorTrayConveyer::isAnySensorGotSignal()
{
    return stcRightTraySensor->get(-1) || stcLeftTraySensor->get(-1);
}

bool SensorTrayConveyer::trayArrivedExit()
{
    if (stoe == nullptr)
    {
        return stcRightTraySensor->get();
    }
    else
    {
        return !stcLeftTraySensor->get() && stcRightTraySensor->get();
    }
}

SensorTrayConveyerConfig *SensorTrayConveyer::getStcConfig() const
{
    return stcConfig;
}

bool SensorTrayConveyer::beltZCanMove() const
{
    return m_beltZCanMove;
}

void SensorTrayConveyer::initEventHandle()
{
    stcKicker = MotionElementContainer::getIns()->getItem<SCCylinder>(CylName::STCOutputKicker);
    stcRightTraySensor = MotionElementContainer::getIns()->getItem<SCDI>(DiName::STCRightTraySNR);
    stcLeftTraySensor = MotionElementContainer::getIns()->getItem<SCDI>(DiName::STCLeftTraySNR);
    stcBeltZ = MotionElementContainer::getIns()->getItem<SCAxis>(AxisName::STCBeltZ);
    stcBelt = MotionElementContainer::getIns()->getItem<SCAxis>(AxisName::STCBelt);

    beltRunDir = SCAxis::DirEnumInfo().nameToEnum(stcConfig->beltRunDirection());
}

void SensorTrayConveyer::startEventHandle(const WorkerEvent &event)
{
    Q_UNUSED(event)
    QVariantList args;
    args << true;
    pushEvent(WorkerEvent("makeSureHasNotTrayAtTheExit", args));
}

void SensorTrayConveyer::stopEventHandle()
{
    stopEventHandled();
}

void SensorTrayConveyer::purgeEventHandle()
{
    purgeEventHandled();
}

void SensorTrayConveyer::homeWorker(bool moveToReadyPosAfterHome)
{
    Q_UNUSED(moveToReadyPosAfterHome)
}
